/*
 * Copyright (c) 2020 hebeiyiliuba.com
 * All rights reserved.
 *
 */
package org.jeecg.common.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Date;
import java.util.UUID;

/**
 * 水印
 *
 * @author duanlikao
 * @created 2021/2/23
 */
@Slf4j
public class WaterMarkUtil {
    // 水印透明度 1 最强，不透明 0 最弱，透明的。
    private static final float alpha = 1.0f; //0.5
    // 水印横向位置
    private static int positionWidth = 100;
    // 水印纵向位置
    private static int positionHeight = 300;
    // 水印文字字体
    private static final Font font = new Font("宋体", Font.BOLD, 30);
    // 水印文字颜色
    private static final Color color = Color.white;

    public static final String MARK_TEXT = "已完成";

    public static final String FONT_NAME = "微软雅黑";
    public static final int FONT_STYLE = Font.BOLD;
    public static final int FONT_SIZE = 30;
    public static final int MARGIN_ALL = 50;
    public static final Color FONT_COLOR = Color.RED;

    public static final int X = 100;
    public static final int Y = 300;

    public static final float ALPHA = 0.3F;

    public static final String LOGO = "Done.png";

    /**
     * 给图片添加水印文字
     *
     * @param text   水印文字
     * @param srcImgPath 源图片路径
     * @param targetPath 目标图片路径
     */
    public static void markImage(String text, String srcImgPath, String targetPath) {
        markImage(text, srcImgPath, targetPath, null);
    }

    /**
     * 给图片添加水印文字、可设置水印文字的旋转角度
     *
     * @param text
     * @param srcImgPath
     * @param targetPath
     * @param degree
     */
    public static void markImage(String text, String srcImgPath, String targetPath, Integer degree) {

        OutputStream os = null;
        try {
            // 0、图片类型
            String type = srcImgPath.substring(srcImgPath.indexOf(".") + 1, srcImgPath.length());

            // 1、源图片
            Image srcImg = ImageIO.read(new File(srcImgPath));

            int imgWidth = srcImg.getWidth(null);
            int imgHeight = srcImg.getHeight(null);

            BufferedImage buffImg = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);

            // 2、得到画笔对象
            Graphics2D g = buffImg.createGraphics();
            // 3、设置对线段的锯齿状边缘处理
            g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g.drawImage(srcImg.getScaledInstance(imgWidth, imgHeight, Image.SCALE_SMOOTH), 0, 0, null);
            // 4、设置水印旋转
            if (null != degree) {
                g.rotate(Math.toRadians(degree), (double) buffImg.getWidth() / 2, (double) buffImg.getHeight() / 2);
            }
            // 5、设置水印文字颜色
            g.setColor(color);
            // 6、设置水印文字Font
            g.setFont(font);
            // 7、设置水印文字透明度
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
            // 8、第一参数->设置的内容，后面两个参数->文字在图片上的坐标位置(x,y)
            positionWidth = 50;
            positionHeight = imgHeight-30;
            g.drawString(text,positionWidth, positionHeight);
            // 9、释放资源
            g.dispose();
            // 10、生成图片
            os = new FileOutputStream(targetPath);
            // ImageIO.write(buffImg, "JPG", os);
            ImageIO.write(buffImg, type.toUpperCase(), os);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != os){
                    os.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 给图片添加水印文字、可设置水印文字的旋转角度
     * @param text
     * @param inputStream
     * @param outputStream
     * @param degree
     * @param typeName
     */
    public static void markImageByIO(String text, InputStream inputStream, OutputStream outputStream,
            Integer degree, String typeName) {
        try {
            // 1、源图片
            Image srcImg = ImageIO.read(inputStream);

            int imgWidth = srcImg.getWidth(null);
            int imgHeight = srcImg.getHeight(null);
            BufferedImage buffImg = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);

            // 2、得到画笔对象
            Graphics2D g = buffImg.createGraphics();
            // 3、设置对线段的锯齿状边缘处理
            g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g.drawImage(srcImg.getScaledInstance(imgWidth, imgHeight, Image.SCALE_SMOOTH), 0, 0, null);
            // 4、设置水印旋转
            if (null != degree) {
                g.rotate(Math.toRadians(degree), (double) buffImg.getWidth() / 2, (double) buffImg.getHeight() / 2);
            }
            // 5、设置水印文字颜色
            g.setColor(color);
            // 6、设置水印文字Font
            g.setFont(font);
            // 7、设置水印文字透明度
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
            // 8、第一参数->设置的内容，后面两个参数->文字在图片上的坐标位置(x,y)

            g.drawString(text, positionWidth, positionHeight);
            // 9、释放资源
            g.dispose();
            // 10、生成图片
            ImageIO.write(buffImg, typeName.toUpperCase(), outputStream);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * imgFile 图像文件
     * imageFileName 图像文件名
     * uploadPath 服务器上上传文件的相对路径
     * realUploadPath 服务器上上传文件的物理路径
     * ① 创建缓存图片
     * ② 创建绘图工具
     * ③ 将原图绘制到缓存图片
     * ④ 将水印logo绘制到缓存图片
     * ⑤ 创建图像编码工具类
     * ⑥ 编码缓存图像生成目标图片
     */
    public String watermarkAdd( String imgFile, String imageFileName, String uploadPath, String realUploadPath ) {

        String imgWithWatermarkFileName = "watermark_" + imageFileName;
        OutputStream os = null;

        try {
            File urlFile = new File(imgFile);
            Image image = ImageIO.read(urlFile);

            int width = image.getWidth(null);
            int height = image.getHeight(null);

            BufferedImage bufferedImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);  // ①
            Graphics2D g = bufferedImage.createGraphics();  // ②
            g.drawImage(image, 0, 0, width,height,null);  // ③

            String logoPath = realUploadPath + "/" + LOGO;  // 水印图片地址
            File logo = new File(logoPath);        // 读取水印图片
            Image imageLogo = ImageIO.read(logo);

            int markWidth = imageLogo.getWidth(null);    // 水印图片的宽度和高度
            int markHeight = imageLogo.getHeight(null);


            int widthDiff = width - markWidth;
            int heightDiff = height - markHeight;

            int x = X;
            int y = Y;
            if(x>widthDiff){
                x = widthDiff;
            }
            if(y>heightDiff){
                y = heightDiff;
            }

            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP,ALPHA));//设置水印
            g.rotate(Math.toRadians(-10), bufferedImage.getWidth()/2, bufferedImage.getHeight()/2);  // 设置水印图片的旋转度


            g.drawImage(imageLogo,x,y,null);//④ x:横坐标，y:纵坐标
            g.dispose();
            // 输出图片
            os = new FileOutputStream(realUploadPath + "/" + imgWithWatermarkFileName);
            ImageIO.write(bufferedImage, "jpg", os);// ⑤// ⑥
            os.flush();
            os.close();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(os!=null){
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return uploadPath + "/" + imgWithWatermarkFileName;
    }

    public static void main(String[] args) {
//        String srcImgPath = "原始图片路径";
//        String text = "内容";
//        //
//        String targerTextPath = "新图片路径+name+后缀";
//        //    String targerTextPath2 = "新图片路径+name+后缀";
//
//        System.out.println("给图片添加水印文字开始...");
//        // 给图片添加水印文字
//        markImage(text, srcImgPath, targerTextPath);
//        // 给图片添加水印文字,水印文字旋转-45
//        //    markImage(text, srcImgPath, targerTextPath2, -45);
//        System.out.println("给图片添加水印文字结束...");

        String urlFile = "/Users/duanlikao/Downloads/WX20211130-132910@2x.png";

//        String a =  new WaterMarkUtil().imageToBase64(urlFile);
//        System.out.println(a);

//        String urlFile1 = "/Users/duanlikao/Downloads/Done.png";
//        String imageFileName = "12345678.png";
        String path  = "/Users/duanlikao/Downloads";
//        String path1  = "/Users/duanlikao/Downloads"; //工业园区二园区29号包头经纬能化有限公司
        String waterMarkContent = "2021-11-03 11:15:02||内蒙古包头市石拐区工业园区二园区29号包头经纬能化有限公司"; //山西省吕梁市中阳县
//        //String url = new WaterMarkUtil().watermarkAdd(urlFile,imageFileName ,path,path1 );
//
//        String url = new WaterMarkUtil().markImageByIcon(urlFile1,urlFile ,path );
//        System.out.println(url);
//
        String url = WaterMarkUtil.waterPress(urlFile, path, Color.GRAY, 30,  waterMarkContent);
        System.out.println(url);

    }

    /**
     * 文字水印
     * @param srcImgPath
     * @param outImgPath
     * @param markContentColor
     * @param fontSize
     * @param waterMarkContent
     * @return
     */
    public static String waterPress(String srcImgPath, String outImgPath,
            Color markContentColor, int fontSize, String waterMarkContent) {
        log.debug("waterPress srcImgPath:{} waterMarkContent :{}",srcImgPath , waterMarkContent);

        String dateString = DateUtils.dateToStringDateTime(new Date());
        String uid =  UUID.randomUUID().toString().replace("-", "");
        String imgWithWatermarkFileName = "watermark_"+dateString+"_"+uid+".jpg" ;
        try {
            String[] waterMarkContents = waterMarkContent.split("\\|\\|");

            // 读取原图片信息
            File srcImgFile = new File(srcImgPath);
            Image srcImg = ImageIO.read(srcImgFile);
            int srcImgWidth = srcImg.getWidth(null);
            int srcImgHeight = srcImg.getHeight(null);
            // 加水印
            BufferedImage bufImg = new BufferedImage(srcImgWidth, srcImgHeight, BufferedImage.TYPE_INT_RGB);
            // 得到画笔对象
            Graphics2D g = bufImg.createGraphics();
            // 数组长度
            int contentLength = waterMarkContents.length;
            // 获取水印文字中最长的
            int maxLength = 0;
            int[] sizes = new int[]{60, 30, 20, 16, 14, 9,  8, 6, 4};
            for (int i = 0; i < contentLength; i++) {
                int fontlen = getWatermarkLength(waterMarkContents[i], g);
                if (maxLength < fontlen) {
                    maxLength = fontlen;
                }
            }

            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
            // 设置起点
            g.drawImage(srcImg, 0, 0, srcImgWidth, srcImgHeight, null);
            //横屏图片使用默认
            //竖屏图片|正方形图片|图片宽度小于水印字体长度 计算字体大小
            if(srcImgWidth < srcImgHeight || srcImgWidth == srcImgHeight || srcImgWidth < maxLength ){
                fontSize = (int) Math.round(srcImgWidth*0.037);
            }

            System.out.println(srcImgWidth+"======"+maxLength+"======"+fontSize);
            Font font = new Font("宋体", Font.PLAIN, fontSize);
            // 根据图片的背景设置水印颜色
            g.setColor(markContentColor);
            // 设置水印文字字体
            g.setFont(font);
            for (int j = 0; j < contentLength; j++) {
                waterMarkContent = waterMarkContents[j];
                int tempX = 10;
                int tempY = fontSize;
                // 单字符长度
                int tempCharLen = 0;
                // 单行字符总长度临时计算
                int tempLineLen = 0;
                StringBuffer sb = new StringBuffer();
                for (int i = 0; i < waterMarkContent.length(); i++) {
                    char tempChar = waterMarkContent.charAt(i);
                    tempCharLen = getCharLen(tempChar, g);
                    tempLineLen += tempCharLen;
                    if (tempLineLen >= srcImgWidth) {
                        // 长度已经满一行,进行文字叠加
                        g.drawString(sb.toString(), tempX, tempY);
                        // 清空内容,重新追加
                        sb.delete(0, sb.length());
                        tempLineLen = 0;
                    }
                    // 追加字符
                    sb.append(tempChar);
                }
                // 通过设置后两个输入参数给水印定位
                g.drawString(sb.toString(), 20, srcImgHeight - (contentLength - j - 1) * tempY-50);
//            //左下角
//            g.drawString(sb.toString(), 0, srcImgHeight - (contentLength - j - 1) * tempY);
//
//            //右下角
//            g.drawString(sb.toString(), srcImgWidth - maxLength, srcImgHeight - (contentLength - j - 1) * tempY);

            }
            g.dispose();
            File file = new File(outImgPath);
            if (!file.exists()) {
                file.mkdirs();// 创建文件根目录
            }

            // 输出图片
            FileOutputStream outImgStream = new FileOutputStream(outImgPath + "/" + imgWithWatermarkFileName);
            ImageIO.write(bufImg, "jpg", outImgStream);
            outImgStream.flush();
            outImgStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        File fileTmp = new File(outImgPath + "/" + imgWithWatermarkFileName);
        return  fileTmp.exists() ? outImgPath + "/" + imgWithWatermarkFileName : StringUtils.EMPTY  ;
    }

    public static int getCharLen(char c, Graphics2D g) {
        return g.getFontMetrics(g.getFont()).charWidth(c);
    }

    /**
     * 获取水印文字总长度
     *
     * @paramwaterMarkContent水印的文字
     * @paramg
     * @return水印文字总长度
     */
    public static int getWatermarkLength(String waterMarkContent, Graphics2D g) {
        return g.getFontMetrics(g.getFont()).charsWidth(
                waterMarkContent.toCharArray(), 0, waterMarkContent.length());
    }


    /**
     * 给图片添加水印、可设置水印图片位置与旋转角
     * @param iconPath      水印图片路径
     * @param srcImgPath    源图片路径
     * @param targerPath    目标图片路径
     * @param location      水印位置：1、左上角，2、右上角，3、左下角，4、右下角，5、中间
     * @param degree        旋转角：顺时针角度
     */
    public static String markImageByIcon(String iconPath, String srcImgPath, String targerPath, Integer location, Integer degree) {

        String dateString = DateUtils.dateToStringDateTime(new Date());
        String imgWithWatermarkFileName = "watermark_"+dateString+".jpeg" ;

        OutputStream os = null;
        try {
            Image srcImg = ImageIO.read(new File(srcImgPath));

            int width = srcImg.getWidth(null);
            int height = srcImg.getHeight(null);

            BufferedImage buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

            // 得到画笔对象
            Graphics2D g = buffImg.createGraphics();

            // 设置对线段的锯齿状边缘处理
            g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);

            g.drawImage(srcImg, 0, 0, width, height, null);

            if (null != degree) {
                // 设置水印旋转
                g.rotate(Math.toRadians(degree), (double) buffImg.getWidth() / 2, (double) buffImg.getHeight() / 2);
            }

            // 水印图象的路径 水印一般为gif或者png的，这样可设置透明度
            ImageIcon imgIcon = new ImageIcon(iconPath);

            // 得到Image对象。
            Image syImg = imgIcon.getImage();

            float alpha = 0.5f; // 透明度

            int syWidth = 300 ; //syImg.getWidth(null);
            int syHeight = 300 ; //syImg.getHeight(null);

            // 如果水印图片高或宽大于目标图片是做的处理，使水印宽或高等于目标图片的宽高，并且等比例缩放
            int newSyWidth = syWidth;
            int newSyHeight = syHeight;

            if (syWidth > width) {
                newSyWidth = width;
                newSyHeight = (int) ((double)newSyWidth / syWidth * height);
            }

            if (newSyHeight > height) {
                newSyHeight = height;
                newSyWidth = (int) ((double)newSyHeight / syHeight * newSyWidth);
            }

            // 根据位置参数确定坐标位置
            int x = 0, y = 0;
            // location 位置： 1、左上角，2、右上角，3、左下角，4、右下角，5、中间
            switch (location) {
            case 1: break;
            case 2:
                x = width - newSyWidth;
                break;
            case 3:
                y = height - newSyHeight;
                break;
            case 4:
                x = width - newSyWidth;
                y = height - newSyHeight;
                break;
            case 5:
                x = (width - newSyWidth) / 2;
                y = (height - newSyHeight) / 2;
                break;
            default: break;
            }

            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));

            // 表示水印图片的位置
            g.drawImage(syImg, x, y, newSyWidth, newSyHeight, null);

            // 水印文件结束
            g.dispose();

            os = new FileOutputStream(targerPath+ "/" + imgWithWatermarkFileName);

            // 生成图片
            ImageIO.write(buffImg, "jpeg", os);

            log.debug("图片完成添加Icon印章... srcImgPath:{}, targerPath:{}", srcImgPath, targerPath);
        } catch (Exception e) {
            log.info("图片添加Icon印章异常！ iconPath:{}, srcImgPath:{}, targerPath:{}, location:{}", iconPath, srcImgPath, targerPath, location);
        } finally {
            try {
                if (null != os) {
                    os.close();
                }
            } catch (Exception e) {
                log.error("", e);
            }
        }
        return targerPath + "/" + imgWithWatermarkFileName;
    }

    /**
     * 给图片添加中间位置水印图
     * @param iconPath 水印图片路径
     * @param srcImgPath 源图片路径
     * @param targerPath 目标图片路径
     */
    public static String markImageByIcon(String iconPath, String srcImgPath, String targerPath) {
       return markImageByIcon(iconPath, srcImgPath, targerPath, 4, null);
    }

    /**
     * 将图片转换成Base64编码
     * @param imgFile 待处理图片
     * @return
     */
    public static String imageToBase64(String imgFile){
        //将图片文件转化为字节数组字符串，并对其进行Base64编码处理
        InputStream in = null;
        byte[] data = null;
        //读取图片字节数组
        try
        {
            in = new FileInputStream(imgFile);
            data = new byte[in.available()];
            in.read(data);
            in.close();
        }catch (IOException e){
            e.printStackTrace();
        }
        return "data:image/jpg;base64,"+ new String(Base64.encodeBase64(data));
        // 对字节数组Base64编码
//        BASE64Encoder encoder = new BASE64Encoder();
//        // 返回Base64编码过的字节数组字符串
//        return "data:image/jpg;base64,"+encoder.encode(Objects.requireNonNull(data));
    }

}
